package org.acghub.mtdb.xmlgen.maker.bean;

import com.alibaba.fastjson2.JSONObject;
import org.acghub.mtdb.common.Bean;
import org.acghub.mtdb.common.Config;
import org.acghub.mtdb.common.Var;
import org.acghub.mtdb.util.StringUtil;
import org.acghub.mtdb.xmlgen.Maker;
import org.acghub.mtdb.xmlgen.visitor.VarMarshalVisitor;
import org.acghub.mtdb.xmlgen.visitor.marshal.DocumentVarMarshalVisitor;
import org.acghub.mtdb.xmlgen.visitor.marshal.FastJson2VarMarshalVisitor;
import org.bson.Document;

import java.io.PrintStream;
import java.util.List;

/**
 * @author zhouhe
 */
public abstract class BeanMarshalMaker extends Maker<Bean> {

    protected final PrintStream ps;
    protected final String prefix;

    public BeanMarshalMaker(Bean inner, Config config, PrintStream ps, String prefix) {
        super(inner, config);
        this.ps = ps;
        this.prefix = prefix;
    }

    @Override
    public void make() throws Exception {
        this.makeMarshal();
        this.makeUnMarshal();
    }

    private void makeMarshal() throws Exception {
        ps.println(prefix + "@Override");
        ps.println(prefix + "public " + getMarshalClassName() + " marshal(" + getMarshalClassName() + " writer) {");
        // var marshal
        for (Var var : this.inner().getVars()) {
            var.accept(this.newVarMarshalVisitor(var, ps, StringUtil.concat(prefix, StringUtil.TAB), true));
        }
        ps.println(StringUtil.concat(prefix, StringUtil.TAB) + "return writer;");
        ps.println(prefix + "}");
        ps.println();
    }

    private void makeUnMarshal() throws Exception {
        ps.println(prefix + "@Override");
        ps.println(prefix + "public " + "void" + " unmarshal(" + getMarshalClassName() + " reader) {");
        // var unmarshal
        for (Var var : this.inner().getVars()) {
            var.accept(this.newVarMarshalVisitor(var, ps, StringUtil.concat(prefix, StringUtil.TAB), false));
        }
        ps.println(prefix + "}");
        ps.println();
    }

    protected abstract String getMarshalClassName();

    protected abstract VarMarshalVisitor newVarMarshalVisitor(Var var, PrintStream ps, String prefix, boolean marshal);

    public static void make(Bean inner, Config config, PrintStream ps, String prefix) throws Exception {
        List<BeanMarshalMaker> beanMarshalMakers = List.of(
                new DocumentBeanMarshalMaker(inner, config, ps, prefix),
                new FastJson2BeanMarshalMaker(inner, config, ps, prefix)
        );
        for (BeanMarshalMaker beanMarshalMaker : beanMarshalMakers) {
            beanMarshalMaker.make();
        }
    }

    static class FastJson2BeanMarshalMaker extends BeanMarshalMaker {

        FastJson2BeanMarshalMaker(Bean inner, Config config, PrintStream ps, String prefix) {
            super(inner, config, ps, prefix);
        }

        @Override
        protected String getMarshalClassName() {
            return JSONObject.class.getName();
        }

        @Override
        protected VarMarshalVisitor newVarMarshalVisitor(Var var, PrintStream ps, String prefix, boolean marshal) {
            return new FastJson2VarMarshalVisitor(var, ps, prefix, marshal);
        }
    }

    /**
     * @author zhouhe
     */
    static class DocumentBeanMarshalMaker extends BeanMarshalMaker {

        DocumentBeanMarshalMaker(Bean inner, Config config, PrintStream ps, String prefix) {
            super(inner, config, ps, prefix);
        }

        @Override
        protected String getMarshalClassName() {
            return Document.class.getName();
        }

        @Override
        protected VarMarshalVisitor newVarMarshalVisitor(Var var, PrintStream ps, String prefix, boolean marshal) {
            return new DocumentVarMarshalVisitor(var, ps, prefix, marshal);
        }
    }
}
